#include "commons.h"

unsigned int ones, tens, hunds, thous, ten_thous, hund_thous, thous_thous; //??????????????
unsigned int period; //pwm
unsigned int timerCounterI = 0, timerCounterJ = 0; //????1ms??????
char UARTFlag = 0;
unsigned int U2RX_Buf;
int LickHistory = 0;
char UartSend[] = {0x55, 0x00, 0x00, 0xAA};

/********************************T2?? (1ms ????****************************************************/

void __attribute__((__interrupt__, no_auto_psv)) _T2Interrupt(void) {
    IFS0bits.T2IF = 0;
    // flag_T2 =1;
    timerCounterI++;
    timerCounterJ++;

    if (LickOnPin) // To record all the licks, including those during ITI.
    {
        Digt_out(1, 1); // lick, BNC 1 will output 1 for 1 ms
        LickHistory = 1;
    }

    //    reaction_time = TMR2;
    //     TMR2 = 0 ;
}

void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void) {
    IFS1bits.U2RXIF = 0;
    UARTFlag = 1;
    U2RX_Buf = U2RXREG; //?UART?????????

    ErrorUartSend();

}

void __attribute__((interrupt, no_auto_psv)) _U2TXInterrupt(void) {
    IFS1bits.U2TXIF = 0; //??????
}

void __attribute__((__interrupt__, no_auto_psv)) _T1Interrupt(void) {
    IFS0bits.T1IF = 0;
}

void __attribute__((__interrupt__, no_auto_psv)) _PWMInterrupt(void) {
    IFS2bits.PWMIF = 0;
}

void Init_LCD(void) {
    DelayNmSec(15);

    //  LATD &= 0xFF00;
    DATA &= 0xFF00; // lcd.c use this
    //DATA = 0x00;  old definition
    RW = 0; // R/W state set low
    RS = 0; // RS state set low
    E = 0; // E state set low
    /* set data and control pins to outputs */
    TRIS_DATA &= 0xFF00; // lcd.c use this
    // 	TRIS_DATA = 0x00;  old definition
    RW_TRIS = 0; // RW pin set as output
    RS_TRIS = 0; // RS pin set as output
    E_TRIS = 0; // E pin set as output


    /* 1st LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;		//old definition
    //DATA = 0x38;		//old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNmSec(5); //5ms

    /* 2nd LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;
    //DATA = 0x38;
    Nop();
    Nop();
    Nop();
    //    E = 0;	//old definition
    E = 1; // lcd.c use this
    DelayNuSec(200); //200us

    /* 3rd LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;	//old definition
    //DATA = 0x38;	//old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNuSec(200); //200us

    lcd_cmd(0x38); //8bit, 5*8, 1/16DUTY
    lcd_cmd(0x06); //AC auto add 1??
    lcd_cmd(0x0c); //display on

}

void Init_PWM(void) {
    unsigned int config; //??PWM?????
    unsigned int sptime; //?????SEVTCMP ????????????
    unsigned int config1; //??PWM??????PTCON?
    unsigned int config2; //????PWMCON1?????
    unsigned int config3; //??????????????????PWMCON2???
    //unsigned int dutycycle=0x03ff;		//?????????????(??????????)
    config = (PWM_INT_EN & PWM_FLTA_DIS_INT & PWM_INT_PR1
            & PWM_FLTA_INT_PR0
            & PWM_FLTB_DIS_INT & PWM_FLTB_INT_PR0); //PWM????;??A????;PWM?????1;??A?????0;??B????;??B?????0
    ConfigIntMCPWM(config); //????PWM????/??;????????


    SetMCPWMDeadTimeAssignment(PWM_DTS1A_UA & //??PWM???????DTCON2?:1H????????????1L??????????
            PWM_DTS1I_UB & PWM_DTS2A_UA & //???A??;1H????????????1L?????????????B??
            PWM_DTS2I_UB);

    SetMCPWMDeadTimeGeneration(PWM_DTBPS8 &
            PWM_DTA54 & PWM_DTAPS8 & PWM_DTB54); //??PWM??????????DTCON1?:????B????1:8;????A????54;
    //????A????1:8;????B????54;
    period = 0x1F00; //??PTPER???????(???????????)
    //period = 0x6168; //20Hz
    sptime = 0x0; //??SEVTCMP?????
    config1 = (PWM_EN & PWM_IDLE_STOP & PWM_OP_SCALE16 &
            PWM_IPCLK_SCALE16 & PWM_MOD_FREE); //PWM??;PWM???????;??????1:16;??????1:16;??????

    config2 = (PWM_PEN4L & PWM_PEN3H & PWM_PEN2H & PWM_PEN1H &
            PWM_PEN4H & PWM_PEN3L & PWM_PEN2L & PWM_PEN1L &
            PWM_MOD1_IND & PWM_MOD2_IND & PWM_MOD3_IND &
            PWM_MOD4_IND); //??PWM1?PWM2?PWM3?PWM4????I/O

    config3 = (PWM_SEVOPS1 & PWM_OSYNC_PWM & PWM_UEN); //????????1:1;?????PWM????;PWM????
    OpenMCPWM(period, sptime, config1, config2, config3); //?PTMR;SEVTCMP;PTCON;PWMCON1;PWMCON2

}

void Init_SPI(void) {
    int SPIcon;
    int SPIstat;
    CloseSPI2();
    SPIcon = FRAME_ENABLE_OFF & FRAME_SYNC_OUTPUT
            & SPI_MODE16_OFF & SPI_CKE_ON
            & CLK_POL_ACTIVE_HIGH
            & MASTER_ENABLE_ON & SEC_PRESCAL_1_1
            & PRI_PRESCAL_1_1 & ENABLE_SDO_PIN;
    SPIstat = SPI_ENABLE & SPI_IDLE_CON
            & SPI_RX_OVFLOW_CLR;
    OpenSPI2(SPIcon, SPIstat);
}

void InitTMR2(void) {
    TMR2 = 0; // clear timer 2
    PR2 = TMR_RATE / 1000; //1ms???
    IFS0bits.T2IF = 0; // clr interrupt flag
    IEC0bits.T2IE = 1; // set interrupt enable bit
    T2CON = 0x8020; //1:64 prescale, open TMR2
    ConfigIntTimer2(T2_INT_PRIOR_5 & T2_INT_ON);
}

void InitTMR1(void) {
    TMR1 = 0; // clear timer 1
    PR1 = TMR_RATE / 10; //100 ms???
    IFS0bits.T1IF = 0; // clr interrupt flag
    IEC0bits.T1IE = 1; // set interrupt enable bit
    T1CON = 0x8020; //1:64 prescale, open TMR1
    ConfigIntTimer1(T1_INT_PRIOR_6 & T1_INT_ON);
}

void SetupPorts(void) {
    PORTB = 0;
    TRISB = 0x0003;
    PORTC = 0;
    TRISC = 0xFFF5;
    PORTD = 0;
    TRISD = 0xFFFF;
    PORTF = 0;
    TRISF = 0xFFFC;
    PORTG = 0;
    TRISG = 0xFC3C;

}

void lcd_cmd(char cmd) {
    RS = 0;
    RW = 0;
    Nop();
    Nop();
    DATA &= 0xFF00; // lcd.c use this
    DATA |= cmd; // lcd.c use this
    //      DATA = 0x00;	// old definition
    //      DATA = cmd;		// old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNmSec(5); //5ms
}

void lcd_data(char data) {
    RS = 1;
    RW = 0;
    Nop();
    Nop();
    DATA &= 0xFF00; // lcd.c use this
    DATA |= data; // lcd.c use this
    //  DATA = 0x00; 	// old definition
    //  DATA = data;	// old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    RS = 0;
    DelayNuSec(400);
}

void puts_lcd(unsigned char *data, unsigned char count) {
    while (count) {
        lcd_data(*data++);
        count--;
    }
}

void LCD_set_xy(unsigned int x, unsigned int y) //??LCD????????????x?y   ?????????X:1-16?Y:1-2
{
    unsigned char address;
    if (y == 1) {
        address = 0x80 - 1 + x;
    } else {
        address = 0xc0 - 1 + x;
    }
    lcd_cmd(address);
}

void counts_dispose(unsigned int counter) {
    ones = 0;
    tens = 0;
    hunds = 0;
    thous = 0;
    ten_thous = 0;
    hund_thous = 0;
    thous_thous = 0;
    while (counter > 0) {

        if (counter > 999999) {
            thous_thous++;
            counter -= 1000000;
        } else if (counter > 99999) {
            hund_thous++;
            counter -= 100000;
        } else if (counter > 9999) {
            ten_thous++;
            counter -= 10000;
        } else if (counter > 999) {
            thous++;
            counter -= 1000;
        } else if (counter > 99) {
            hunds++;
            counter -= 100;
        } else if (counter > 9) {
            tens++;
            counter -= 10;
        } else {
            ones++;
            counter--;

        }
    };

    ones += 0x30;
    tens += 0x30;
    hunds += 0x30;
    thous += 0x30;
    ten_thous += 0x30;
    hund_thous += 0x30;
    thous_thous += 0x30;


}

void beep(void) {
    PORTDbits.RD11 = 1;
    DelayNmSec(300);
    PORTDbits.RD11 = 0;
}

void Valve_ON(unsigned int N, unsigned int rate) {
    Valve_ON_w_BNC(N, rate, 2);
}

void Valve_ON_w_BNC(unsigned int N, unsigned int rate, unsigned int Out) {
    switch (N) {
        case 1: PORTBbits.RB6 = 1;
            PDC4 = rate;
            break;
        case 2: PORTBbits.RB3 = 1;
            PDC4 = rate;
            Digt_out(Out, 2);
            break; // ValveA ON, BNC2=1 for 2 ms
        case 3: PORTBbits.RB7 = 1;
            PDC4 = rate;
            Digt_out(Out, 2);
            break; // ValveB ON, BNC3=1 for 2 ms


            //case 2:  PORTBbits.RB3=1; PDC4=rate;  break;
            //case 3:  PORTBbits.RB7=1; PDC4=rate;  break;

        case 4: PORTBbits.RB2 = 1;
            PDC4 = rate;
            break;
        case 5: PORTBbits.RB5 = 1;
            PDC3 = rate;
            Digt_out(Out, 2);
            break;
        case 6: PORTGbits.RG8 = 1;
            PDC3 = rate;
            Digt_out(Out, 2);
            break;
        case 7: PORTBbits.RB4 = 1;
            PDC3 = rate;
            Digt_out(Out, 2);
            break;
        case 8: PORTGbits.RG9 = 1;
            PDC3 = rate;
            Digt_out(Out, 2);
            break;
        case 9: PORTGbits.RG6 = 1;
            PDC2 = rate;
            Digt_out(Out, 2);
            break;
        case 10: PORTCbits.RC1 = 1;
            PDC2 = rate;
            Digt_out(Out, 2);
            break;
        case 11: PORTGbits.RG7 = 1;
            PDC2 = rate;
            Digt_out(Out, 2);
            break;
        case 12: PORTCbits.RC3 = 1;
            PDC2 = rate;
            Digt_out(Out, 2);
            break;
        case 13: PORTGbits.RG1 = 1;
            PDC1 = rate;
            Digt_out(Out, 2);
            break;
        case 14: PORTFbits.RF0 = 1;
            PDC1 = rate;
            Digt_out(Out, 2);
            break;
        case 15: PORTGbits.RG0 = 1;
            PDC1 = rate;
            Digt_out(Out, 2);
            break;
        case 16: PORTFbits.RF1 = 1;
            PDC1 = rate;
            Digt_out(Out, 2);
            break;
    }
    // UartSend[2] = 1;
    // puts_lcd((unsigned char*)&UartSend[0], sizeof(UartSend));


}

void Valve_OFF(unsigned int N) {
    Valve_OFF_w_BNC(N, 2);
}

void Valve_OFF_w_BNC(unsigned int N, unsigned int Out) {
    switch (N) {
        case 1: PORTBbits.RB6 = 0;
            break;
        case 2: PORTBbits.RB3 = 0;
            Digt_out(Out, 2);
            break; // ValveA OFF, BNC2=1 for 2 ms
        case 3: PORTBbits.RB7 = 0;
            Digt_out(Out, 2);
            break; // ValveB OFF, BNC3=1 for 2 ms

            //case 2:  PORTBbits.RB3=0;   break;
            //case 3:  PORTBbits.RB7=0;   break;
        case 4: PORTBbits.RB2 = 0;
            break;
        case 5: PORTBbits.RB5 = 0;
            Digt_out(Out, 2);
            break;
        case 6: PORTGbits.RG8 = 0;
            Digt_out(Out, 2);
            break;
        case 7: PORTBbits.RB4 = 0;
            Digt_out(Out, 2);
            break;
        case 8: PORTGbits.RG9 = 0;
            Digt_out(Out, 2);
            break;
        case 9: PORTGbits.RG6 = 0;
            Digt_out(Out, 2);
            break;
        case 10: PORTCbits.RC1 = 0;
            Digt_out(Out, 2);
            break;
        case 11: PORTGbits.RG7 = 0;
            Digt_out(Out, 2);
            break;
        case 12: PORTCbits.RC3 = 0;
            Digt_out(Out, 2);
            break;
        case 13: PORTGbits.RG1 = 0;
            Digt_out(Out, 2);
            break;
        case 14: PORTFbits.RF0 = 0;
            Digt_out(Out, 2);
            break;
        case 15: PORTGbits.RG0 = 0;
            Digt_out(Out, 2);
            break;
        case 16: PORTFbits.RF1 = 0;
            Digt_out(Out, 2);
            break;
    }
    // UartSend[2] = 0;
    // puts_lcd((unsigned char*)&UartSend[0], sizeof(UartSend));

}

void DelayNmSec(unsigned int N) {
    unsigned int j;
    while (N--)
        for (j = 0; j < MILLISEC; j++);
}

// definition is same with previous board

void DelayNuSec(unsigned int N) {
    unsigned int j;
    while (N--)
        for (j = 0; j < uSEC; j++);

}

void DelayNmSecNew(unsigned int N) // This is right. Hou Han
{
    while (N--) {
        timerCounterJ = 0;
        while (timerCounterJ < 1) {
        }
    }

}

/***************************************************/
void InitADC10(void) {

    ADPCFG = 0xFFBF; // all PORTB = Digital; RB2 = analog
    ADCON1 = 0x0000; // SAMP bit = 0 ends sampling ...
    // and starts converting
    ADCHS = 0x0006; // Connect RB6/AN6 as CH0 input  ..
    // in this example RB2/AN2 is the input
    ADCSSL = 0;
    ADCON3 = 0x0002; // Manual Sample, Tad = internal 2 Tcy
    ADCON2 = 0;


    ADCON1bits.ADON = 1; // turn ADC ON
}

/*****************************************************/
void Digt_out(unsigned int Nchan, unsigned int Duration) // digital output in 1
{
    switch (Nchan) {

            /*	case 1:     //A
                            Out1 = 1;
                            DelayNuSec(400*Duration);
                            Out1 = 0;; //
                            break;  */


        case 1: //A
            Out1 = 1;
            DelayNuSec(400 * Duration);
            Out1 = 0;
            ; //
            break;

        case 2: // light on during delay
            Out2 = 1;
            //DelayNmSecNew(1000*Duration);

            DelayNuSec(400 * Duration);

            Out2 = 0; //
            break;

        case 3: //AB
            Out3 = 1;
            DelayNuSec(400 * Duration);
            Out3 = 0;
            ; //
            break;
        case 4: //AB
            Out4 = 1;
            DelayNuSec(400 * Duration);
            Out4 = 0;
            ; //
            break;
        case 5: //AB
            Out5 = 1;
            DelayNuSec(400 * Duration);
            Out5 = 0;
            ; //
            break;
        case 6: //AB
            Out6 = 1;
            DelayNuSec(400 * Duration);
            Out6 = 0;
            ; //
            break;
        case 7: //AB
            Out7 = 1;
            DelayNuSec(400 * Duration);
            Out7 = 0;
            ; //
            break;
        case 8: //AB
            Out8 = 1;
            DelayNuSec(400 * Duration);
            Out8 = 0;
            ; //
        default:
            break;
    }
}

void InitUART2(void) {
    unsigned int baudvalue;
    unsigned int U2MODEvalue;
    unsigned int U2STAvalue;
    CloseUART2(); //??UART??
    ConfigIntUART2(UART_RX_INT_EN & UART_RX_INT_PR6 &
            UART_TX_INT_DIS & UART_TX_INT_PR2); //?UART?????????????????6???????????2
    U2MODEvalue = UART_EN & UART_IDLE_CON &
            UART_DIS_WAKE & UART_DIS_LOOPBACK &
            UART_DIS_ABAUD & UART_NO_PAR_8BIT&
            UART_1STOPBIT; //UART2?????U1MODE??:UART??;????????;?????????
    //??;??????;?ICx(U2RX)?????????;8????????;1????
    U2STAvalue = UART_INT_TX_BUF_EMPTY &
            UART_TX_PIN_NORMAL &
            UART_TX_ENABLE & UART_INT_RX_CHAR &
            UART_ADR_DETECT_DIS &
            UART_RX_OVERRUN_CLEAR; //UART2????????U2STA??:??????????;U2TX??????;UART?
    //?;?????char???IF??;??????;?????0
    baudvalue = ((FCY / 16) / BAUDRATE) - 1; //????????
    OpenUART2(U2MODEvalue, U2STAvalue, baudvalue); //?U2MODE,U2STA,U2BRG?????dsPIC
}

void UART2PutChar(unsigned char Ch) {
    // wait for empty buffer
    while (BusyUART2());
    U2TXREG = Ch;
}

void Puts_UART2(unsigned char *data, unsigned char count) {
    while (count) {
        UART2PutChar(*data++);
        count--;
    }
}

void localSendTwice(int thisSp) {
    UartSend[1] = thisSp;
    UartSend[2] = 1;
    puts_lcd((unsigned char*) &UartSend[0], sizeof (UartSend));

    DelayNmSecNew(2);

    UartSend[1] = thisSp;
    UartSend[2] = 0;
    puts_lcd((unsigned char*) &UartSend[0], sizeof (UartSend));
}

void localSendOnce(int thisSp, int thisValue) {
    UartSend[1] = thisSp;
    UartSend[2] = thisValue;
    puts_lcd((unsigned char*) &UartSend[0], sizeof (UartSend));
}

void ErrorUartSend(void) {
    // UartSend is a global variable, just send it again without chaning anything
    puts_lcd((unsigned char*) &UartSend[0], sizeof (UartSend));
}

void NewDigt_out(unsigned int Nchan, float Duration) // digital output in 1
{
    switch (Nchan) {


        case 1: //A
            Out1 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out1 = 0;
            ; //
            break;

        case 2: // light on during delay
            Out2 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out2 = 0; //
            break;

        case 3: //AB
            Out3 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out3 = 0;
            ; //
            break;
        case 4: //AB
            Out4 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }
            Out4 = 0;
            ; //
            break;

        case 5: //AB
            Out5 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out5 = 0;
            ; //
            break;
        case 6: //AB
            Out6 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out6 = 0;
            ; //
            break;
        case 7: //AB
            Out7 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out7 = 0;
            ; //
            break;
        case 8: //AB
            Out8 = 1;

            timerCounterI = 1;
            while (timerCounterI < 1000 * Duration) {
            }

            Out8 = 0;
            ; //
            break;
        default:
            break;
    }
}

void BNCController(int Channel, int State) {
    switch (Channel) {
        case 1: //A
            Out1 = State;
            break;
        case 2: // light on during delay
            Out2 = State;
            break;
        case 3: //AB
            Out3 = State;
            break;
        case 4: //AB
            Out4 = State;
            break;
        case 5: //AB
            Out5 = State;
            break;
        case 6: //AB
            Out6 = State;
            break;
        case 7: //AB
            Out7 = State;
            break;
        case 8: //AB
            Out8 = State;
            break;
        default:
            break;
    }
}


